1use crate::vm::executor::error_handler::ExecutionError;
44use crate::vm::executor::instruction_handlers::{
45 ArithmeticHandler, BuiltinCallsHandler, ComparisonHandler, ControlFlowHandler, HeapOpsHandler,
46 StackOpsHandler,
47};
48use crate::vm::executor::traits::{HeapOperations, StackOperations, VariableManager};
49use crate::vm::frame::Frame;
50use crate::vm::instructions::Instruction;
51use crate::vm::registers::Registers;
52use crate::vm::types::ArraySize;
53use crate::vm::value::Value;
54
55pub struct InstructionDispatcher;
60
61impl InstructionDispatcher {
62 pub fn execute_instruction<S, H, V>(
103 instruction: &Instruction,
104 stack: &mut S,
105 heap: &mut H,
106 variable_manager: &mut V,
107 frame: &mut Frame,
108 registers: &mut Registers,
109 builtins: &mut crate::runtime::builtins::Builtins,
110 ) -> Result<Option<usize>, ExecutionError>
111 where
112 S: StackOperations,
113 H: HeapOperations,
114 V: VariableManager,
115 {
116 match instruction {
117 Instruction::PushConst(idx) => {
118 let value = frame.get_constant(*idx).unwrap_or(Value::Undefined);
119 stack.push(value);
120 Ok(None)
121 }
122 Instruction::Pop => {
123 StackOpsHandler::pop(stack)?;
124 Ok(None)
125 }
126 Instruction::Dup => {
127 StackOpsHandler::dup(stack)?;
128 Ok(None)
129 }
130 Instruction::Add => {
131 ArithmeticHandler::add(stack)?;
132 Ok(None)
133 }
134 Instruction::Sub => {
135 ArithmeticHandler::subtract(stack)?;
136 Ok(None)
137 }
138 Instruction::Mul => {
139 ArithmeticHandler::multiply(stack)?;
140 Ok(None)
141 }
142 Instruction::Div => {
143 ArithmeticHandler::divide(stack)?;
144 Ok(None)
145 }
146 Instruction::Mod => {
147 ArithmeticHandler::modulo(stack)?;
148 Ok(None)
149 }
150 Instruction::Exp => {
151 ArithmeticHandler::power(stack)?;
152 Ok(None)
153 }
154 Instruction::Inc => {
155 ArithmeticHandler::increment(stack)?;
156 Ok(None)
157 }
158 Instruction::Dec => {
159 ArithmeticHandler::decrement(stack)?;
160 Ok(None)
161 }
162 Instruction::And => {
163 ComparisonHandler::logical_and(stack)?;
164 Ok(None)
165 }
166 Instruction::Or => {
167 ComparisonHandler::logical_or(stack)?;
168 Ok(None)
169 }
170 Instruction::Not => {
171 ComparisonHandler::logical_not(stack)?;
172 Ok(None)
173 }
174 Instruction::Xor => {
175 ComparisonHandler::bitwise_xor(stack)?;
176 Ok(None)
177 }
178 Instruction::Eq => {
179 ComparisonHandler::equal(stack)?;
180 Ok(None)
181 }
182 Instruction::Ne => {
183 ComparisonHandler::not_equal(stack)?;
184 Ok(None)
185 }
186 Instruction::Lt => {
187 ComparisonHandler::less_than(stack)?;
188 Ok(None)
189 }
190 Instruction::Le => {
191 ComparisonHandler::less_equal(stack)?;
192 Ok(None)
193 }
194 Instruction::Gt => {
195 ComparisonHandler::greater_than(stack)?;
196 Ok(None)
197 }
198 Instruction::Ge => {
199 ComparisonHandler::greater_equal(stack)?;
200 Ok(None)
201 }
202 Instruction::StrictEq => {
203 ComparisonHandler::strict_equal(stack)?;
204 Ok(None)
205 }
206 Instruction::StrictNe => {
207 ComparisonHandler::strict_not_equal(stack)?;
208 Ok(None)
209 }
210 Instruction::LoadGlobal(idx) => {
211 let value = variable_manager
212 .get_global((*idx).into())
213 .unwrap_or(&Value::Undefined)
214 .clone();
215 stack.push(value);
216 Ok(None)
217 }
218 Instruction::StoreGlobal(idx) => {
219 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
220 variable_manager.set_global((*idx).into(), value);
221 Ok(None)
222 }
223 Instruction::LoadLocal(idx) => {
224 let value = variable_manager
225 .get_local((*idx).into())
226 .unwrap_or(&Value::Undefined)
227 .clone();
228 stack.push(value);
229 Ok(None)
230 }
231 Instruction::StoreLocal(idx) => {
232 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
233 variable_manager.set_local((*idx).into(), value);
234 Ok(None)
235 }
236 Instruction::LoadArg(idx) => {
237 let value = variable_manager
238 .get_argument((*idx).into())
239 .unwrap_or(&Value::Undefined)
240 .clone();
241 stack.push(value);
242 Ok(None)
243 }
244 Instruction::LoadThisFunction => {
245 let function_handle = frame.function_handle.clone().unwrap_or_else(|| {
246 crate::vm::handle::FunctionHandle::new(crate::vm::handle::HeapHandleId::new(0))
247 });
248 stack.push(Value::Function(function_handle));
249 Ok(None)
250 }
251 Instruction::LoadThis => {
252 let this_value = frame.this_value.clone().unwrap_or(Value::Undefined);
253 stack.push(this_value);
254 Ok(None)
255 }
256 Instruction::LoadClosureVar(name) => {
257 let value = frame
258 .closure_vars
259 .get(name)
260 .cloned()
261 .unwrap_or(Value::Undefined);
262 stack.push(value);
263 Ok(None)
264 }
265 Instruction::Jump(target_ip) => {
266 let new_ip =
267 ControlFlowHandler::jump::<S, V>(stack, registers, (*target_ip).into())?;
268 Ok(Some(new_ip))
269 }
270 Instruction::JumpIfTrue(target_ip) => {
271 let new_ip = ControlFlowHandler::jump_if_true::<S, V>(
272 stack,
273 registers,
274 (*target_ip).into(),
275 )?;
276 Ok(Some(new_ip))
277 }
278 Instruction::JumpIfFalse(target_ip) => {
279 let new_ip = ControlFlowHandler::jump_if_false::<S, V>(
280 stack,
281 registers,
282 (*target_ip).into(),
283 )?;
284 Ok(Some(new_ip))
285 }
286 Instruction::Call(function_index) => {
287 ControlFlowHandler::call::<S, V>(
288 stack,
289 registers,
290 frame,
291 (*function_index).as_usize().into(),
292 )?;
293 Ok(None)
294 }
295 Instruction::Return => {
296 let new_ip =
297 ControlFlowHandler::return_from_function::<S, V>(stack, registers, frame)?;
298 Ok(Some(new_ip))
299 }
300 Instruction::NewObject => {
301 HeapOpsHandler::alloc_object(stack, heap)?;
302 Ok(None)
303 }
304 Instruction::NewArray(_size) => {
305 HeapOpsHandler::alloc_array(stack, heap)?;
306 Ok(None)
307 }
308 Instruction::SetProperty => {
309 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
310 let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
311 let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
312
313 if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
314 HeapOpsHandler::set_object_property(stack, heap, handle, key, value)?;
315 }
316 Ok(None)
317 }
318 Instruction::SetPropertyAssign => {
319 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
320 let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
321 let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
322
323 if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
324 HeapOpsHandler::set_object_property(stack, heap, handle, key, value)?;
325 }
326 Ok(None)
327 }
328 Instruction::GetProperty => {
329 let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
330 let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
331
332 if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
333 HeapOpsHandler::get_object_property(stack, heap, handle, key)?;
334 }
335 Ok(None)
336 }
337 Instruction::TypeOf => {
338 let value = stack.peek().ok_or(ExecutionError::StackUnderflow)?;
339 let type_name = match value {
340 Value::Number(_) => "number",
341 Value::String(_) => "string",
342 Value::Boolean(_) => "boolean",
343 Value::Object(_) => "object",
344 Value::Array(_) => "array",
345 Value::Function(_) => "function",
346 Value::Null => "null",
347 Value::Undefined => "undefined",
348 };
349 stack.push(Value::String(type_name.to_string()));
350 Ok(None)
351 }
352 Instruction::InstanceOf => {
353 let constructor = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
354 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
355
356 let result = match (value, constructor) {
357 (Value::Object(_), Value::Function(_)) => true,
358 _ => false,
359 };
360
361 stack.push(Value::Boolean(result));
362 Ok(None)
363 }
364 Instruction::In => {
365 let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
366 let object = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
367
368 let result = match (object, property_key) {
369 (Value::Object(handle), Value::String(key)) => {
370 heap.has_object_property(handle.id(), &key)
371 }
372 _ => false,
373 };
374
375 stack.push(Value::Boolean(result));
376 Ok(None)
377 }
378 Instruction::Delete => {
379 let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
380 let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
381
382 if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
383 HeapOpsHandler::remove_object_property(stack, heap, handle, key)?;
384 }
385 Ok(None)
386 }
387 Instruction::New => {
388 let constructor = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
389 if let Value::Function(_) = constructor {
390 HeapOpsHandler::alloc_object(stack, heap)?;
391 }
392 Ok(None)
393 }
394 Instruction::NewClass => {
395 HeapOpsHandler::alloc_object(stack, heap)?;
396 Ok(None)
397 }
398 Instruction::GetPrototype => {
399 let object = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
400 if let Value::Object(handle) = object {
401 let prototype = heap
402 .get_object_property(handle.id(), "__proto__")
403 .unwrap_or(&Value::Undefined)
404 .clone();
405 stack.push(prototype);
406 }
407 Ok(None)
408 }
409 Instruction::SetPrototype => {
410 let prototype = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
411 let object = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
412
413 if let Value::Object(handle) = object {
414 heap.set_object_property(handle.id(), "__proto__".to_string(), prototype);
415 }
416 Ok(None)
417 }
418 Instruction::Await => {
419 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
420 stack.push(value);
421 Ok(None)
422 }
423 Instruction::Yield => {
424 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
425 stack.push(value);
426 Ok(None)
427 }
428 Instruction::Throw => {
429 ControlFlowHandler::throw::<S, V>(stack, registers)?;
430 Ok(None)
431 }
432 Instruction::Try(try_block_size, catch_block_size) => {
433 let new_ip = ControlFlowHandler::try_catch::<S, V>(
434 stack,
435 registers,
436 frame,
437 (*try_block_size).into(),
438 (*catch_block_size).into(),
439 )?;
440 Ok(Some(new_ip))
441 }
442 Instruction::Catch => Ok(None),
443 Instruction::Finally => {
444 let new_ip = ControlFlowHandler::finally::<S, V>(stack, registers, frame)?;
445 Ok(Some(new_ip))
446 }
447 Instruction::Spread => {
448 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
449 stack.push(value);
450 Ok(None)
451 }
452 Instruction::Destructure => Ok(None),
453 Instruction::OptionalChain => Ok(None),
454 Instruction::NullishCoalesce => {
455 let right = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
456 let left = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
457
458 let result = match left {
459 Value::Null | Value::Undefined => right,
460 _ => left,
461 };
462
463 stack.push(result);
464 Ok(None)
465 }
466 Instruction::PushNull => {
467 stack.push(Value::Null);
468 Ok(None)
469 }
470 Instruction::PushUndefined => {
471 stack.push(Value::Undefined);
472 Ok(None)
473 }
474 Instruction::PushTrue => {
475 stack.push(Value::Boolean(true));
476 Ok(None)
477 }
478 Instruction::PushFalse => {
479 stack.push(Value::Boolean(false));
480 Ok(None)
481 }
482 Instruction::PushSymbol(idx) => {
483 let symbol = frame
484 .get_constant(*idx)
485 .unwrap_or(Value::String("Symbol".to_string()));
486 stack.push(symbol);
487 Ok(None)
488 }
489 Instruction::PushBigInt(idx) => {
490 let bigint = frame.get_constant(*idx).unwrap_or(Value::Number(0.0));
491 stack.push(bigint);
492 Ok(None)
493 }
494 Instruction::CallFunction(_function_index, arg_count) => {
495 ControlFlowHandler::call::<S, V>(stack, registers, frame, (*arg_count).into())?;
496 Ok(None)
497 }
498 Instruction::CallBuiltin(function_name, arg_count) => {
499 BuiltinCallsHandler::call_builtin(
500 stack,
501 variable_manager,
502 builtins,
503 function_name.clone(),
504 (*arg_count).into(),
505 )?;
506 Ok(None)
507 }
508 Instruction::RemoveObjectProperty => {
509 let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
510 let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
511
512 if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
513 HeapOpsHandler::remove_object_property(stack, heap, handle, key)?;
514 }
515 Ok(None)
516 }
517 Instruction::CallObjectMethod(method_name, arg_count) => {
518 let object = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
519 if let Value::Object(handle) = object {
520 let method = heap
521 .get_object_property(handle.id(), method_name)
522 .unwrap_or(&Value::Undefined)
523 .clone();
524 stack.push(method);
525 BuiltinCallsHandler::call_builtin(
526 stack,
527 variable_manager,
528 builtins,
529 method_name.clone(),
530 (*arg_count).into(),
531 )?;
532 }
533 Ok(None)
534 }
535 Instruction::CallArrayMethod(method_name, arg_count) => {
536 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
537 if let Value::Array(handle) = array {
538 let method = heap
539 .get_array_element(handle.id(), ArraySize::new(0))
540 .unwrap_or(&Value::Undefined)
541 .clone();
542 stack.push(method);
543 BuiltinCallsHandler::call_builtin(
544 stack,
545 variable_manager,
546 builtins,
547 method_name.clone(),
548 (*arg_count).into(),
549 )?;
550 }
551 Ok(None)
552 }
553 Instruction::GetArrayLength => {
554 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
555 if let Value::Array(handle) = array {
556 let length = heap.get_array_length(handle.id());
557 stack.push(Value::Number(length as f64));
558 }
559 Ok(None)
560 }
561 Instruction::RemoveArrayElement(index) => {
562 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
563 if let Value::Array(handle) = array {
564 let element = heap
565 .get_array_element(handle.id(), *index)
566 .unwrap_or(&Value::Undefined)
567 .clone();
568 stack.push(element);
569 }
570 Ok(None)
571 }
572 Instruction::PushArrayElement => {
573 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
574 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
575
576 if let Value::Array(handle) = array {
577 HeapOpsHandler::push_array_element(stack, heap, handle, value)?;
578 }
579 Ok(None)
580 }
581 Instruction::PopArrayElement => {
582 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
583 if let Value::Array(handle) = array {
584 let element = heap
585 .get_array_element(handle.id(), ArraySize::new(0))
586 .unwrap_or(&Value::Undefined)
587 .clone();
588 stack.push(element);
589 }
590 Ok(None)
591 }
592 Instruction::ShiftArrayElement => {
593 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
594 if let Value::Array(handle) = array {
595 let element = heap
596 .get_array_element(handle.id(), ArraySize::new(0))
597 .unwrap_or(&Value::Undefined)
598 .clone();
599 stack.push(element);
600 }
601 Ok(None)
602 }
603 Instruction::UnshiftArrayElement(size) => {
604 let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
605 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
606
607 if let Value::Array(handle) = array {
608 heap.set_array_element(handle.id(), *size, value);
609 }
610 Ok(None)
611 }
612 Instruction::SliceArray(start, end) => {
613 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
614 if let Value::Array(handle) = array {
615 let start_idx = usize::from(*start);
616 let end_idx = usize::from(*end);
617
618 let mut elements = Vec::new();
619 for i in start_idx..end_idx {
620 if let Some(element) =
621 heap.get_array_element(handle.id(), ArraySize::new(i))
622 {
623 elements.push(element.clone());
624 }
625 }
626
627 let new_array = heap.alloc_array();
628 let new_handle =
629 crate::vm::handle::HeapHandle::<crate::vm::handle::ArrayEntry>::new(
630 new_array,
631 );
632
633 for (i, element) in elements.iter().enumerate() {
634 heap.set_array_element(new_array, ArraySize::new(i), element.clone());
635 }
636
637 stack.push(Value::Array(new_handle));
638 }
639 Ok(None)
640 }
641 Instruction::ConcatArray(count) => {
642 let mut arrays = Vec::new();
643 for _ in 0..(*count).into() {
644 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
645 if let Value::Array(handle) = array {
646 arrays.push(handle);
647 }
648 }
649
650 let result_array = heap.alloc_array();
651 let result_handle =
652 crate::vm::handle::HeapHandle::<crate::vm::handle::ArrayEntry>::new(
653 result_array,
654 );
655
656 let mut index = 0;
657 for array_handle in arrays.iter().rev() {
658 let length = heap.get_array_length(array_handle.id());
659 for i in 0..length {
660 if let Some(element) =
661 heap.get_array_element(array_handle.id(), ArraySize::new(i))
662 {
663 heap.set_array_element(
664 result_array,
665 ArraySize::new(index),
666 element.clone(),
667 );
668 index += 1;
669 }
670 }
671 }
672
673 stack.push(Value::Array(result_handle));
674 Ok(None)
675 }
676 Instruction::IndexOfArray(_target) => {
677 let target_value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
678 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
679
680 if let Value::Array(handle) = array {
681 let length = heap.get_array_length(handle.id());
682 let mut found_index = -1;
683
684 for i in 0..length {
685 if let Some(element) =
686 heap.get_array_element(handle.id(), ArraySize::new(i))
687 {
688 if element == &target_value {
689 found_index = i as i32;
690 break;
691 }
692 }
693 }
694
695 stack.push(Value::Number(found_index as f64));
696 }
697 Ok(None)
698 }
699 Instruction::IncludesArray(_target) => {
700 let target_value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
701 let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
702
703 if let Value::Array(handle) = array {
704 let length = heap.get_array_length(handle.id());
705 let mut found = false;
706
707 for i in 0..length {
708 if let Some(element) =
709 heap.get_array_element(handle.id(), ArraySize::new(i))
710 {
711 if element == &target_value {
712 found = true;
713 break;
714 }
715 }
716 }
717
718 stack.push(Value::Boolean(found));
719 }
720 Ok(None)
721 }
722 Instruction::Halt => Ok(None),
723 }
724 }
725}